﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using SeasideResearch.LibCurlNet;

namespace SemestralniPraceY35VAN
{
    class Category
    {

        /* *********************************************************************
         * STATIC VARIABLES
         * ********************************************************************/

        /// <summary>
        /// 
        /// </summary>
        private static string xmlData;

        /// <summary>
        /// 
        /// </summary>
        private static Dictionary<string, Category> categoriesDict;

        /// <summary>
        /// 
        /// </summary>
        private static ArrayList categoriesTree;

        /// <summary>
        /// 
        /// </summary>
        public static ArrayList Categories
        {
            get
            {
                if (categoriesDict == null)
                {
                    LoadCategories();
                }

                return categoriesTree;
            }
        }

        /* *********************************************************************
         * VARIABLES
         * ********************************************************************/

        /// <summary>
        /// Properties of the category.
        /// </summary>
        private Hashtable properties;

        /// <summary>
        /// 
        /// </summary>
        private ArrayList children;
        
        /// <summary>
        /// 
        /// </summary>
        public string ID { get { if (properties.ContainsKey("id")) return (string)properties["id"]; else return ""; } }

        /// <summary>
        /// 
        /// </summary>
        public string FullPathName { get { if (properties.ContainsKey("fullpathname")) return (string)properties["fullpathname"]; else return ""; } }

        /// <summary>
        /// 
        /// </summary>
        public string NodeName { get { if (properties.ContainsKey("nodename")) return (string)properties["nodename"]; else return ""; } }

        /// <summary>
        /// 
        /// </summary>
        public string Src { get { if (properties.ContainsKey("iconurl")) return (string)properties["iconurl"]; else return ""; } }

        /// <summary>
        /// Icon of the category.
        /// </summary>
        public Image Icon
        {
            get
            {
                if (!properties.ContainsKey("icon"))
                {
                    properties.Add("icon", Downloader.DownloadImage((string)properties["iconurl"]));
                }

                return (Image)properties["icon"];
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ArrayList Children { get { return children; } }

        /* *********************************************************************
         * CONSTRUCTOR
         * ********************************************************************/

        /// <summary>
        /// 
        /// </summary>
        /// <param name="category"></param>
        public Category(XmlNode category)
        {
            properties = new Hashtable();
            children = new ArrayList();

            if (category.Name == "category" || category.Name == "primarycategory")
            {
                for (int i = 0; i < category.ChildNodes.Count; i++)
                {
                    switch (category.ChildNodes[i].Name)
                    {
                        case "categories":
                            for (int j = 0; j < category.ChildNodes[i].ChildNodes.Count; j++)
                            {
                                Category cat = new Category(category.ChildNodes[i].ChildNodes[j]);

                                children.Add(cat);

                                if (cat.ID != null && category.Name != "primarycategory")
                                {
                                    categoriesDict.Add(cat.ID, cat);
                                }
                            }
                            break;
                        default:
                            properties.Add(category.ChildNodes[i].Name, category.ChildNodes[i].InnerText);
                            break;
                    }
                }
            }
            else
            {
                throw new IOException("Not Category!");
            }
        }

        /* *********************************************************************
         * STATIC FUNCTIONS
         * ********************************************************************/

        /// <summary>
        /// 
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="size"></param>
        /// <param name="nmemb"></param>
        /// <param name="extraData"></param>
        /// <returns></returns>
        private static int OnWriteData(byte[] buf, int size, int nmemb, object extraData)
        {
            xmlData += System.Text.Encoding.UTF8.GetString(buf);

            return size * nmemb;
        }

        /// <summary>
        /// 
        /// </summary>
        private static void LoadCategories()
        {
            xmlData = "";

            categoriesTree = new ArrayList();

            categoriesDict = new Dictionary<string, Category>();

            // downloading file

            Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);

            Easy easy = new Easy();

            Easy.WriteFunction writeFunction = new Easy.WriteFunction(OnWriteData);

            easy.SetOpt(CURLoption.CURLOPT_URL, @"http://api.foursquare.com/v1/categories");
            easy.SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, writeFunction);
            easy.SetOpt(CURLoption.CURLOPT_USERAGENT, Foursquare.USER_AGENT);

            easy.Perform();
            easy.Cleanup();

            Curl.GlobalCleanup();

            // processing file

            XmlDocument xml = Downloader.stringToXml(xmlData);

            XmlNode categories = xml.GetElementsByTagName("categories")[0];

            for (int i = 0; i < categories.ChildNodes.Count; i++)
            {
                if (categories.ChildNodes[i].Name == "category")
                {
                    Category category = new Category(categories.ChildNodes[i]);

                    categoriesTree.Add(category);

                    if (category.ID != null)
                    {
                        categoriesDict.Add(category.ID, category);
                    }
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static Category GetCategory(string id)
        {
            if (categoriesDict == null)
            {
                LoadCategories();
            }

            if (categoriesDict.ContainsKey(id))
            {
                return categoriesDict[id];
            }
            else
            {
                return null;
            }
        }
    }
}
